package com.hongji.lms5xxcommunicator.opc.client;

import com.hongji.lms5xxcommunicator.exception.OpcConnectionException;
import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue;
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;

import java.util.List;

/**
 * <p>OPC UA 客户端服务接口。</p>
 *
 * <p><b>职责：</b></p>
 * <ul>
 *   <li>测试 OPC UA 服务器的连通性；</li>
 *   <li>节点值的读取（单点 / 批量）；</li>
 *   <li>节点值的写入（兼容多种类型，包括 ByteString/byte[]）；</li>
 *   <li>节点 ID 的校验与解析。</li>
 * </ul>
 *
 * <p><b>用法：</b></p>
 * <ol>
 *   <li>通过 Spring 注入实现类，例如 {@code @Autowired OpcUaClientService client}；</li>
 *   <li>调用 {@link #testConnection(String)} 先验证连通性；</li>
 *   <li>使用 {@link #readSingleNode(String)} / {@link #readSingleNode(NodeId)} 或
 *       {@link #readMultipleNodes(List)} 获取节点值；</li>
 *   <li>调用 {@link #writeSingleNode(String, Object)} 写入数据；</li>
 *   <li>必要时使用 {@link #validateNodeId(String)} 校验 NodeId 格式。</li>
 * </ol>
 *
 * @since 1.0
 */
public interface OpcUaClientService {

    /**
     * <p>测试与指定 OPC UA 服务器的连通性。</p>
     *
     * @param endpointUrl 服务器端点 URL
     * @return {@code true} 表示连接成功
     * @throws OpcConnectionException 连接失败时抛出
     */
    boolean testConnection(String endpointUrl) throws OpcConnectionException;

    /**
     * <p>读取单个节点的值（字符串形式的 NodeId）。</p>
     *
     * @param nodeId 节点 ID 字符串（支持 ns= / nsu= 等多种格式）
     * @return 节点当前值（Variant 的内部 Java 对象）
     * @throws OpcConnectionException 读取失败时抛出
     */
    Object readSingleNode(String nodeId) throws OpcConnectionException;

    /**
     * <p>读取单个节点的值（NodeId 对象）。</p>
     *
     * @param nodeId {@link NodeId} 对象
     * @return 节点当前值（Variant 的内部 Java 对象）
     * @throws OpcConnectionException 读取失败时抛出
     */
    Object readSingleNode(NodeId nodeId) throws OpcConnectionException;

    /**
     * <p>批量读取多个节点的值。</p>
     *
     * @param nodeIds 节点 ID 字符串列表
     * @return 与请求顺序一一对应的 {@link DataValue} 列表
     * @throws OpcConnectionException 读取失败时抛出
     */
    List<DataValue> readMultipleNodes(List<String> nodeIds) throws OpcConnectionException;

    /**
     * <p>写入单个节点的值。</p>
     *
     * <p><b>说明：</b></p>
     * <ul>
     *   <li>支持与目标节点数据类型兼容的 Java 类型；</li>
     *   <li>包括 {@code ByteString} 或 {@code byte[]}。</li>
     * </ul>
     *
     * @param nodeId 节点 ID 字符串
     * @param value  待写入的值
     * @return {@code true} 表示写入成功（状态码为 Good）
     * @throws OpcConnectionException 写入失败或类型不兼容时抛出
     */
    boolean writeSingleNode(String nodeId, Object value) throws OpcConnectionException;

    /**
     * <p>校验并解析节点 ID 字符串。</p>
     *
     * @param nodeId 节点 ID 字符串
     * @return 解析后的 {@link NodeId} 对象
     * @throws IllegalArgumentException 当输入格式非法时抛出
     */
    NodeId validateNodeId(String nodeId);
}
